<script setup>
import { nextTick, ref } from "vue";
import { Background } from "@vue-flow/background";
import { VueFlow, useVueFlow } from "@vue-flow/core";
import { MiniMap } from "@vue-flow/minimap";
import { Controls, ControlButton } from "@vue-flow/controls";
import { DagreLayoutUtil } from "./utils//DagreLayoutUtil";
import Icon from "./components/Icon.vue";
import NodeTypeMenu from "./components/NodeTypeMenu.vue";
// ------------------------------------------------------------
import BaseNode from "./components/nodes/other/base/BaseNode.vue";
import StartNode from "./components/nodes/atomic/start/StartNode.vue";
import EndNode from "./components/nodes/atomic/end/EndNode.vue";
import NullNode from "./components/nodes/other/null/NullNode.vue";
import IfNode from "./components/nodes/branch/if/IfNode.vue";
import CodeBlock from "./components/nodes/sentence/code-block/CodeBlock.vue";

import AddNodeEdge from "./components/edge/AddNodeEdge.vue";

// ------------------------------------------------------------------
const nodes = ref([
  { id: "start", type: "start", label: "input", position: { x: 200, y: 400 } },
  { id: "end", type: "end", label: "Output 8", position: { x: 350, y: 600 } },
]);

const edges = ref([
  {
    id: "start-end",
    source: "start",
    target: "end",
    type: "add-node",
    data: { text: "custom edge" },
    // 动画
    animated: true,
    
    // label: () => h(CustomEdgeLabel, { label: 'custom label text' }),
    // markerEnd: MarkerType.ArrowClosed,
  },
]);

// our dark mode toggle flag
const dark = ref(false);
const onAddNode = (info) => {
  console.log({ edges: edges.value });
};

/**
 * To update a node or multiple nodes, you can
 * 1. Mutate the node objects *if* you're using `v-model`
 * 2. Use the `updateNode` method (from `useVueFlow`) to update the node(s)
 * 3. Create a new array of nodes and pass it to the `nodes` ref
 */
const layoutUtil = new DagreLayoutUtil({
  rankdir: "TB",
  nodesep: 300,
  ranksep: 300,
});
function updatePos() {
  // nodes.value = nodes.value.map((node) => {
  //   return {
  //     ...node,
  //     position: {
  //       x: Math.random() * 400,
  //       y: Math.random() * 400,
  //     },
  //   }
  // })

  nodes.value = layoutUtil.applyLayout(nodes.value, edges.value);
}

/**
 * toObject transforms your current graph data to an easily persist-able object
 */
function logToObject() {
  console.log();
}

/**
 * Resets the current viewport transformation (zoom & pan)
 */
function resetTransform() {
  // setViewport({ x: 0, y: 0, zoom: 1 });
}

function toggleDarkMode() {
  dark.value = !dark.value;
}
const useVueFlowUtils = useVueFlow();
const { removeEdges, addNodes, addEdges } = useVueFlowUtils;

const currentEdge = ref(null);
const addNodeWithType = (node) => {
  console.log({ node });
  const newNodeId = `node-${Date.now()}`;

  if (node.onNodeAdd) {
    node.onNodeAdd(currentEdge.value, useVueFlowUtils);
  } else {
    addNodes({
      id: newNodeId,
      data: { label: "Node 2" },
      position: { x: 100, y: 100 },
      type: 'base',
    });

    removeEdges([currentEdge.value.id]);

    addEdges([
      {
        id: `edge-${newNodeId}-source`,
        source: currentEdge.value.source,
        target: newNodeId,
        type: "add-node",
        style: currentEdge.value.style,
      },
      {
        id: `edge-${newNodeId}-target`,
        source: newNodeId,
        target: currentEdge.value.target,
        type: "add-node",
        style: currentEdge.value.style,
      },
    ]);
  }

  // 更新布局
  nextTick(() => {
    updatePos();
  });
};

const showNodeTypes = ref(false);

const menuPosition = ref({
  x: 0,
  y: 0,
});
const onChangeNodeTypeShow = ({ show, position, edge }) => {
  menuPosition.value = position;
  currentEdge.value = edge;
  showNodeTypes.value = !showNodeTypes.value;

  console.log({ show, position, edge });
};
</script>

<template>
  <NodeTypeMenu
    :visible="showNodeTypes"
    :position="menuPosition"
    @select="addNodeWithType"
    @close="showNodeTypes = false"
  />
  <VueFlow
    v-model:nodes="nodes"
    v-model:edges="edges"
    class="basic-flow"
    :class="{ dark }"
    fit-view-on-init
  >
    <!-- 自定义节点 -->
    <template #node-null="props">
      <NullNode :id="props.id" :node="props" />
    </template>
    <template #node-start="props">
      <StartNode :id="props.id" :node="props" />
    </template>
    <template #node-end="props">
      <EndNode :id="props.id" :node="props" />
    </template>
    <template #node-if="props">
      <IfNode :id="props.id" :node="props" />
    </template>
    <template #node-base="props">
      <BaseNode :id="props.id" :node="props" />
    </template>
    <template #node-code-block="props">
      <CodeBlock :id="props.id" :node="props" />
    </template>
    

    <!-- 自定义边缘 -->
    <template #edge-add-node="EdgeProps">
      <AddNodeEdge
        :id="EdgeProps.id"
        :source="EdgeProps.source"
        :target="EdgeProps.target"
        :source-x="EdgeProps.sourceX"
        :source-y="EdgeProps.sourceY"
        :target-x="EdgeProps.targetX"
        :target-y="EdgeProps.targetY"
        :source-position="EdgeProps.sourcePosition"
        :target-position="EdgeProps.targetPosition"
        :marker-end="EdgeProps.markerEnd"
        :style="EdgeProps.style"
        @onAddNode="onAddNode"
        @onChangeNodeTypeShow="onChangeNodeTypeShow"
      />
    </template>

    <!-- 背景网格 -->
    <Background pattern-color="#aaa" gap="20" />

    <!-- 控制面板 -->
    <Controls position="bottom-left">
      <ControlButton title="Reset Transform" @click="resetTransform">
        <Icon name="reset" />
      </ControlButton>

      <ControlButton title="Shuffle Node Positions" @click="updatePos">
        <Icon name="update" />
      </ControlButton>

      <ControlButton title="Toggle Dark Mode" @click="toggleDarkMode">
        <Icon v-if="dark" name="sun" />
        <Icon v-else name="moon" />
      </ControlButton>

      <ControlButton title="Log `toObject`" @click="logToObject">
        <Icon name="log" />
      </ControlButton>
    </Controls>

    <!-- 小地图 -->
    <MiniMap />
  </VueFlow>
</template>
